'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.java.exception.UnsupportedOperationException import UnsupportedOperationException

# import java.util.Iterator;
# import java.util.function.Consumer;
# import java.util.stream.Stream;

'''
 * a WrappedIterator is an ExtendedIterator wrapping around a plain (or
 * presented as plain) Iterator. The wrapping allows the usual extended
 * operations (filtering, concatenating) to be done on an Iterator derived
 * from some other source.
 * <br>
'''


class WrappedIterator:
    '''
     * set to <code>True</code> if self wrapping doesn't permit the use of
     * .remove(). Otherwise the .remove() is delegated to the base iterator.
    '''

    # protected boolean removeDenied

    def __init__(self, ite, removeDenied):
        self.base = ite
        self.removeDenied = removeDenied

    '''
     * Answer an ExtendedIterator returning the elements of <code>it</code>.
     * If <code>it</code> is itself an ExtendedIterator, return that otherwise
     * wrap <code>it</code>.
    '''

    # param Iterator it
    # result static  ExtendedIterator
    @staticmethod
    def create(it):
        # return it instanceof ExtendedIterator<?> ? (ExtendedIterator) it : WrappedIterator<>(it, False)
        return WrappedIterator(it, False)

    '''
     * Answer an ExtendedIterator wrapped round <code>it</code> which does not
     * permit <code>.remove()</code> even if <code>it</code> does.
    '''

    # param Iterator it
    # result static  WrappedIterator
    @staticmethod
    def createNoRemove(it):
        return WrappedIterator(it, True)

    '''
     * Answer an ExtendedIterator wrapped round a:@link Stream. The extended
     * iterator does not permit <code>.remove()</code>.
     * <p>
     * The stream should not be used directly. The effect of doing so is
     * undefined.
    '''
    # param Stream stream
    # result static  WrappedIterator
    # def ofStream(self, stream):
    #     return WrappedIterator(stream.iterator(), True):

    # @Override
    # param 
    # result void
    # def close(self):
    #     stream.close()

    '''
     * Given an Iterator that returns Iterator's, self creates an
     * Iterator over the next level values.
     * Similar to list splicing in lisp.
    '''

    # param Iterator<Iterator> it
    # result static  ExtendedIterator
    # @staticmethod
    # def createIteratorIterator(it):
    #     ExtendedIterator
    #     retval = NullIterator.instance()
    #     while (it.hasNext()):
    #         retval = retval.andThen(it.next())
    #
    #     return retval

    '''
     * hasNext: defer to the base iterator
    '''

    # @Override
    # param 
    # result boolean
    def hasNext(self):
        return self.base.hasNext()

    '''
     * next: defer to the base iterator
    '''

    # @Override
    # param 
    # result T
    def next(self):
        return self.base.next()

    '''
     * forEachRemaining: defer to the base iterator
    '''

    # @Override
    # param Consumer<? super T> action
    # result void
    # def forEachRemaining(self, super):
    #     self.base.forEachRemaining(action)

    # @Override
    # param 
    # result void
    def remove(self):
        if self.removeDenied:
            raise UnsupportedOperationException('can not remove this iterator')
        self.base.remove()

    '''
     * close: defer to the base, iff it is closable
    '''

    # @Override
    # param 
    # result void
    def close(self):
        self.base.close()

    '''
     * if <code>it</code> is a Closableiterator, close it. Abstracts away from
     * tests [that were] scattered through the code.
    '''
    # param Iterator<?> it
    # result static void
    # def close(self, it):
    #     NiceIterator.close(it)
